//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.carhailing.system.service.Impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carhailing.common.domain.*;
import com.carhailing.common.result.Result;
import com.carhailing.system.constant.RedisKeyContents;
import com.carhailing.system.mapper.CouponActiveMapper;
import com.carhailing.system.service.CouponActiveService;
import com.carhailing.system.service.CouponService;
import com.carhailing.system.service.CouponUserMiddleService;
import com.carhailing.system.service.DriverUserService;

import java.util.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import static net.sf.jsqlparser.parser.feature.Feature.execute;

@Service
public class CouponActiveServiceImpl extends ServiceImpl<CouponActiveMapper, CouponActive> implements CouponActiveService {
    private static final Logger log = LogManager.getLogger(CouponActiveServiceImpl.class);
    @Autowired
    private CouponActiveMapper couponActiveMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private DriverUserService driverUserService;
    @Autowired
    private CouponUserMiddleService couponUserMiddleService;
    @Autowired
    private CouponService couponService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    public static final String SECKILL_LUA =
            "if tonumber(redis.call('exists', KEYS[1])) == 0 then\n" +
                    "redis.call('set', KEYS[1], ARGV[1], 'EX', ARGV[3])\n" +
                    "end\n" +

                    "if tonumber(redis.call('exists', KEYS[2])) == 0 then\n" +
                    "redis.call('sadd', KEYS[2], '0')\n" +
                    "end\n" +

                    "if tonumber(redis.call('get', KEYS[1])) > 0 and redis.call('sismember', KEYS[2], ARGV[2])==0 then\n" +
                    "redis.call('decr', KEYS[1])\n" +
                    "redis.call('sadd', KEYS[2], ARGV[2])\n" +
                    " return 1\n" +
                    "else\n" +
                    "return 0\n" +
                    "end";

    public Result seckillCoupon(Long couponActiveId,Long couponId) throws Exception {
        //查询最近三天的信息
         List<CouponActive> couponActives = CouponActiveList();
        for (CouponActive couponActive : couponActives) {
             CouponActive active = couponActiveMapper.selectById(couponActiveId);
             Coupon coupon = couponService.getById(couponId);

            if(active==null){
                return Result.error("活动不存在");
            }
            if(active.getCouponActiveStatus()==0){
                return Result.error("场次未开启");
            }
            if(active.getCouponActiveStatus()==2){
                return Result.error("活动已结束");
            }
            if(System.currentTimeMillis()<active.getCouponActiveStartTime().getTime()||System.currentTimeMillis()>active.getCouponActiveEndTime().getTime()){
                return Result.error("活动不在范围内");
            }
            if(coupon.getCouponsTotal()<coupon.getCouponsClaimed()){
                return Result.error("优惠卷已经抢完");
            }
            //重复抢劵
            //DriverUser driverUser = driverUserService.DriverUserInfo();
             User user = new User();
            user.setUserId(1);
            Map<Object,Object> map = stringRedisTemplate.opsForHash().entries(RedisKeyContents.COUPON_USER_MIDDLE+user.getUserId());
             boolean hasClaimed = map.values().stream().anyMatch(value -> ((CouponUserMiddle) value).getCouponId().equals(couponId));
            if (hasClaimed) {
                return Result.error("您已领取过此优惠券");
            }
            //预减库存
            List<Object> keys = new ArrayList<>();
            keys.add("COUPON_SECKILL_REDIS"+ couponActiveId);//库存
            keys.add("COUPON_SECKILL_UERSID_REDIS"+couponActiveId);
            DefaultRedisScript<Long>  script = new DefaultRedisScript<>(SECKILL_LUA, Long.class);
             Long excute = (Long)redisTemplate.execute(script, keys, String.valueOf(coupon.getCouponsTotal()), String.valueOf(user.getUserId()), "86400");
            log.info("excute:"+excute);
            if(!Long.valueOf(1L).equals(excute)){
                return Result.error("优惠券已被抢完");
            }
            //更新缓存
            active.setCouponsClaimed(active.getCouponsClaimed()+1);
            //给用户发卷
            addUserCouponToMq(active);
        }
        return null;
    }

    //添加用户优惠卷到mq
    private void addUserCouponToMq(CouponActive active) {
         CouponUserMiddle couponUserMiddle = new CouponUserMiddle();
         couponUserMiddle.setCouponName(active.getCouponActiveName());
         couponUserMiddle.setUseStatus(0);
         couponUserMiddle.setCouponId(active.getCouponId());
         couponUserMiddle.setCouponEnd(active.getCouponActiveEndTime());
         couponUserMiddle.setCouponStart(active.getCouponActiveStartTime());
         couponUserMiddle.setUserId(1L);
         rabbitTemplate.convertAndSend("COUPON_USER",couponUserMiddle,message ->{
             message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
             return message;
         });
    }


    /**
     * 添加优惠券 优惠卷信息到redis
     * @return
     */
    public Result addCouponActive(CouponActive couponActive) {
        Integer i =  couponActiveMapper.insert(couponActive);
        if (i > 0) {
            HashMap<String, Object> map = new HashMap();
            map.put(RedisKeyContents.ACTIVITY_INFO, JSONUtil.toJsonStr(couponActive));
            map.put(RedisKeyContents.TOTAL_NUMBER, String.valueOf(couponActive.getCouponsTotal()));
            String format = String.format(RedisKeyContents.COUPON_ACTIVE_ID, couponActive.getCouponActiveId());
            stringRedisTemplate.opsForHash().putAll(format, map);
            return Result.success("添加成功");
        }
        return null;
    }


    /**
     * 用户优惠卷记录表
     * @return
     */
    @Override
    public List<CouponUserMiddle> CouponUserMiddleList() {
        final User user = new User();
        user.setUserId(1);
        List<CouponUserMiddle> list = new ArrayList<>();
        Map<Object,Object> map = stringRedisTemplate.opsForHash().entries(RedisKeyContents.COUPON_USER_MIDDLE+user.getUserId());
        Set<Map.Entry<Object,Object>> entries = map.entrySet();
        for (Map.Entry<Object,Object> entry : entries) {
            CouponUserMiddle couponUserMiddle = (CouponUserMiddle) map.get(entry);
            list.add(couponUserMiddle);
        }
        if (list.isEmpty()) {
             List<CouponUserMiddle> userMiddleList = couponUserMiddleService.list();
            for (CouponUserMiddle couponUserMiddle : userMiddleList) {
                stringRedisTemplate.opsForHash().put(RedisKeyContents.COUPON_USER_MIDDLE+user.getUserId(),couponUserMiddle.getCouponId(),couponUserMiddle);
            }
            return userMiddleList;
        }
        return list;
    }


    //查询最近三天的优惠卷活动场次信息
    public List<CouponActive> CouponActiveList() {
        List<CouponActive> list = new ArrayList<>();
        Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(RedisKeyContents.COUPON_ACTIVE_KEY);
        Set<Map.Entry<Object, Object>> entries = map.entrySet();
        for (Map.Entry<Object, Object> entry : entries) {
            CouponActive active = (CouponActive) map.get(entry);
            list.add(active);
        }
        if (list.isEmpty()) {
            List<CouponActive> couponActives = couponActiveMapper.selectThreeDayActive();
            for (CouponActive couponActive : couponActives) {
                stringRedisTemplate.opsForHash().put(RedisKeyContents.COUPON_ACTIVE_KEY,
                        couponActive.getCouponActiveId().toString(),
                        couponActives.toString());
            }
            return couponActives;
        }
        return list;
    }
}
